#include "ultrasonic_gpio.h"
#include "../../CLOCK/clock.h"

#define ULTRASONIC_TIMEOUT_MS  (10)

void Ultrasonic_Init(void)
{
    // 确保GPIO已经初始化（在SYSCFG_DL_init中已调用）
    // 设置初始状态：TRIG引脚为低电平
    DL_GPIO_clearPins(GPIO_ULTRASONIC_PIN_TRIG_PORT, GPIO_ULTRASONIC_PIN_TRIG_PIN);
    
    // 等待系统稳定
    mspm0_delay_ms(100);
}

uint16_t Read_Ultrasonic(void)
{
    unsigned long start, cur;
    uint16_t distVal;
    uint32_t timer_count;

    mspm0_get_clock_ms(&start);
    DL_Timer_setTimerCount(TIMER_ULTRASONIC_INST, 0);
    DL_Timer_clearInterruptStatus(TIMER_ULTRASONIC_INST, DL_TIMER_INTERRUPT_LOAD_EVENT);

    // 发送触发脉冲：先确保TRIG为低电平
    DL_GPIO_clearPins(GPIO_ULTRASONIC_PIN_TRIG_PORT, GPIO_ULTRASONIC_PIN_TRIG_PIN);
    mspm0_delay_us(2);  // 确保低电平持续2us
    
    // 发送10us高电平脉冲
    DL_GPIO_setPins(GPIO_ULTRASONIC_PIN_TRIG_PORT, GPIO_ULTRASONIC_PIN_TRIG_PIN);
    mspm0_delay_us(10);  // 10us高电平脉冲
    DL_GPIO_clearPins(GPIO_ULTRASONIC_PIN_TRIG_PORT, GPIO_ULTRASONIC_PIN_TRIG_PIN);

    // 等待ECHO引脚变高，表示开始接收回声
    while (!DL_GPIO_readPins(GPIO_ULTRASONIC_PIN_ECHO_PORT, GPIO_ULTRASONIC_PIN_ECHO_PIN))
    {
        mspm0_get_clock_ms(&cur);
        if(cur >= (start + ULTRASONIC_TIMEOUT_MS))
        {
            return 0;  // 超时，没有检测到回声开始
        }
    }

    // 开始计时
    DL_Timer_startCounter(TIMER_ULTRASONIC_INST);

    // 等待ECHO引脚变低，表示回声结束
    while (DL_GPIO_readPins(GPIO_ULTRASONIC_PIN_ECHO_PORT, GPIO_ULTRASONIC_PIN_ECHO_PIN))
    {
        if(DL_Timer_getRawInterruptStatus(TIMER_ULTRASONIC_INST, DL_TIMER_INTERRUPT_LOAD_EVENT))
        {
            DL_Timer_stopCounter(TIMER_ULTRASONIC_INST);
            return 0;  // 超时，回声信号太长
        }
    }

    // 停止计时并获取计数值
    DL_Timer_stopCounter(TIMER_ULTRASONIC_INST);
    timer_count = DL_Timer_getTimerCount(TIMER_ULTRASONIC_INST);
    
    // 计算距离
    // 定时器频率：400kHz，每个计数 = 2.5us
    // 声速：340m/s = 0.034cm/us
    // 距离 = (时间 * 声速) / 2
    // distVal = (timer_count * 2.5us * 0.034cm/us) / 2
    // distVal = timer_count * 0.0425 cm
    distVal = (uint16_t)(timer_count * 0.0425f);
    
    return distVal;
}